/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package runebound.ui.mapa;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.Shape;
import java.awt.geom.Ellipse2D;
import java.util.ArrayList;
import java.util.List;
import runebound.basedatos.Camino;
import runebound.basedatos.Conector;
import runebound.basedatos.FronteraConexion;
import runebound.basedatos.Rio;
import runebound.modelo.Ciudad;
import runebound.modelo.Gema;
import runebound.modelo.TipoAmenaza;
import runebound.modelo.heores.Heroe;
import runebound.ui.RBPalentaColores;

/**
 *
 * @author Miguel (alakat@gmail.com)
 */
public class TileMapa {

    private static final int XLEN = 50;
    private static final int YLEN = 40;
    private static final boolean PINTAR_COORDENADAS = true;

    /**
     * @return the XLEN
     */
    public static int getXLEN() {
        return XLEN;
    }

    /**
     * @return the YLEN
     */
    public static int getYLEN() {
        return YLEN;
    }
    private Terreno terreno;
    private boolean gemaAgotada;
    private int x;
    private int y;
    private List<Heroe> heroe;
    private Conector conector;
    private Gema gema;
    private Ciudad ciudad;
    private EstadoTileMapa estado;

    /**
     *
     * @param terreno
     * @param x
     * @param y
     */
    public TileMapa(Terreno terreno, int x, int y) {
        this.terreno = terreno;
        this.x = x;
        this.y = y;
        this.heroe = new ArrayList<>();
        this.gema = null;
        this.estado = EstadoTileMapa.ESPERA;
        this.gemaAgotada = false;
    }

    /**
     *
     * @param terreno
     * @param x
     * @param y
     * @param gema
     */
    public TileMapa(Terreno terreno, int x, int y, Gema gema) {
        this.terreno = terreno;
        this.x = x;
        this.y = y;
        this.heroe = new ArrayList<>();
        this.gema = gema;
    }

    public void paint(Graphics g) {
        pintarEscentario(g);

    }

    private void pintarEscentario(Graphics g) {
        g.setColor(Color.GREEN);
        Polygon p = paintHex(g);
        if (PINTAR_COORDENADAS) {
            paintCoordenadas(g);
        }
        paintConectores(g);
        paintGema(g);
        paintCiudad(g);
        paintEstado(g, p);
        if (this.heroe.size() > 0) {
            g.setFont(new Font("Arial", Font.BOLD, 14));
            g.setColor(RBPalentaColores.getInstance().getColorHeroes());
            //TODO: pintar varios heroes
            g.drawString("H", (XLEN / 2) - 10, (YLEN / 2) + 5);
        }
    }

    private void paintCoordenadas(Graphics g) {
        /*
         Pintamos coordenadas de la celda
         */
        String cad = this.getX() + "," + this.getY();
        g.drawString(cad, 5, 25);
    }

    /**
     * PPintamos el estado de la celda
     *
     * @param g
     * @param p
     */
    private void paintEstado(Graphics g, Polygon p) {
        switch (this.estado) {
            case ESPERA:
                break;
            case HEROE_ACTIVO:
                g.setColor(RBPalentaColores.getInstance().getColorTileHeroeActivo());
                g.fillPolygon(p);
                break;
            case TILE_ACESIBLE:
                g.setColor(RBPalentaColores.getInstance().getColorTileAccesible());
                g.fillPolygon(p);
                break;
        }
    }

    /**
     * Pintamos el hexagono base de la celda
     *
     * @param g
     * @return
     */
    private Polygon paintHex(Graphics g) {
        Polygon p = new Polygon(new int[]{((0 * getXLEN()) / 4), ((1 * getXLEN()) / 4), ((3 * getXLEN()) / 4), ((4 * getXLEN()) / 4), ((3 * getXLEN()) / 4), ((1 * getXLEN()) / 4)},
                new int[]{((2 * getYLEN()) / 4), ((4 * getYLEN()) / 4), ((4 * getYLEN()) / 4), ((2 * getYLEN()) / 4), ((0 * getYLEN()) / 4), ((0 * getYLEN()) / 4)}, 6);
        g.setColor(RBPalentaColores.getInstance().getColorByTerreno(Terreno.LLANURA));
        g.fillPolygon(p);
        g.setColor(RBPalentaColores.getInstance().getColorByTerreno(this.getTerreno()));
        switch (this.getTerreno()) {
            case RIO:
                g.fillRect(10, 0, 10, 20);
                break;
            case CAMINO:
                g.fillRect(10, 0, 10, 20);
                break;
            case CIUDAD:
                g.fillRect(10, 10, 20, 20);
                break;
            case COLINA:
                g.fillPolygon(p);
                break;
            case MONTANYA:
                g.setColor(RBPalentaColores.getInstance().getColorByTerreno(Terreno.COLINA));
                g.fillPolygon(p);
                g.setColor(RBPalentaColores.getInstance().getColorByTerreno(Terreno.MONTANYA));
                int[] xs_ = {10, 20, 30};
                int[] ys_ = {35, 10, 35};
                g.fillPolygon(xs_, ys_, 3);
                break;
            case PANTANO:
                g.fillPolygon(p);
                break;
            case BOSQUE:
                g.fillPolygon(p);
                break;
            case LLANURA:
                break;
        }
        g.setColor(Color.black);
        g.drawPolygon(p);
        return p;
    }

    /**
     * Pintamos los conectores Rios y Caminos
     *
     * @param g
     */
    private void paintConectores(Graphics g) {
        if (conector != null) {
            /*
             Pintamos rios y caminos
             */
            if (conector instanceof Rio) {
                g.setColor(RBPalentaColores.getInstance().getColorByTerreno(Terreno.RIO));
            } else if (conector instanceof Camino) {
                g.setColor(RBPalentaColores.getInstance().getColorByTerreno(Terreno.CAMINO));
            }

            Point pcenter = new Point(TileMapa.XLEN / 2, TileMapa.YLEN / 2);
            Point pConector = this.getPointFronteraConector(this.conector.getEntrada());
            g.drawLine(pConector.x, pConector.y, pcenter.x, pcenter.y);
            pConector = this.getPointFronteraConector(this.conector.getSalida());
            g.drawLine(pConector.x, pConector.y, pcenter.x, pcenter.y);
        }
    }

    /**
     * Pintamos la ciudad
     *
     * @param g
     */
    private void paintCiudad(Graphics g) {
        if (ciudad != null) {
            g.setColor(Color.black);
            g.setFont(new Font("Arial", Font.ITALIC & Font.BOLD, 10));
            g.drawString(this.ciudad.getTitulo(), 5, 12);
        }
    }

    /**
     * Pintamos la gemas y los soles
     *
     * @param g
     * @throws NumberFormatException
     */
    private void paintGema(Graphics g) throws NumberFormatException {
        if (this.isGema()) {
            if (this.gema.isSol()) {
                Shape circle = new Ellipse2D.Float(Float.valueOf("" + XLEN) / 4.0f, Float.valueOf("" + XLEN) / 4.0f, 20.0f, 20.0f);
                g.setColor(RBPalentaColores.getInstance().getColorSol());
                ((Graphics2D) g).fill(circle);
            }
            if (!this.gemaAgotada) {
                g.setColor(RBPalentaColores.getInstance().getColorByTipoAmenaza(this.gema.getTipoAmenaza()));
                Shape circle = new Ellipse2D.Float(2.5f + Float.valueOf("" + XLEN) / 4.0f, 2.5f + Float.valueOf("" + XLEN) / 4.0f, 15.0f, 15.0f);
                ((Graphics2D) g).fill(circle);
            }
        }
    }

    /**
     * @return the terreno
     */
    public Terreno getTerreno() {
        return terreno;
    }

    /**
     * @return the x
     */
    public int getX() {
        return x;
    }

    /**
     * @return the y
     */
    public int getY() {
        return y;
    }

    /**
     * @return the heroe
     */
    public List<Heroe> getHeroe() {
        return heroe;
    }

    /**
     * @return the gema
     */
    public boolean isGema() {
        return gema != null;
    }

    /**
     * Asigna un rio o camino al conector
     *
     * @param rio
     */
    public void setConector(Conector rio) {
        this.conector = rio;
    }

    private Point getPointFronteraConector(FronteraConexion entrada) {
        int x = 0;
        int y = 0;
        switch (entrada) {
            case S:
                x = XLEN / 2;
                y = YLEN;
                break;
            case SE:
                x = XLEN / 8;
                y = (3 * YLEN) / 4;
                break;
            case SO:
                x = (7 * XLEN) / 8;
                y = (3 * YLEN) / 4;
                break;
            case N:
                x = (XLEN) / 2;
                y = 0;
                break;
            case NE:
                x = XLEN / 8;
                y = (YLEN) / 4;
                break;
            case NO:
                x = (7 * XLEN) / 8;
                y = (YLEN) / 4;
                break;

        }
        return new Point(x, y);
    }

    public Gema getGema() {
        return gema;
    }

    public void setGema(Gema gema) {
        this.gema = gema;
    }

    public void setCiudad(Ciudad ciudad) {
        this.ciudad = ciudad;
        ciudad.setTilemap(this);
    }

    public void setEstado(EstadoTileMapa estado) {
        this.estado = estado;
    }

    /**
     * Comprueba si el terreno recibido por parámetro es accesible para este
     *
     * @param terreno
     * @return
     */
    public boolean isTerrenoAccesible(Terreno terreno) {
        if (this.conector != null) {
            return ((this.conector instanceof Rio) && (terreno == Terreno.RIO))
                    || ((this.conector instanceof Camino) && (terreno == Terreno.CAMINO));
        }
        return this.terreno == terreno;

    }

    @Override
    public String toString() {
        return "TileMapa{" + "terreno=" + terreno + ", x=" + x + ", y=" + y + ", gema=" + gema + '}';
    }

    public void aventuraAcabada() {
        this.gemaAgotada = true;
    }

    /**
     * Nos indica si hay aventura disponible
     * @return 
     */
    public boolean isAventura() {
        return this.isGema()&& !this.gemaAgotada;
    }

    /**
     * Indica si la celda es una ciudad
     * @return 
     */
    public boolean isCiudad() {
        return this.ciudad!=null;
    }

    public Ciudad getCiudad() {
        return ciudad;
    }

    
}
